#include<iostream>
#include<string>
#include<strings.h>
#include<unistd.h>
#include <sys/types.h>         
#include <sys/socket.h>
#include <arpa/inet.h>
#include"LOG.hpp"
#include"InetAddr.hpp"
const static int defaultsockfd = -1;
const static int gbacklog = 16;
enum
{
    SOCKET_ERROR=1,
    BIND_ERROR,
    USAGE_ERROR,
    LISTEN_ERROR
};
class TcpServer
{
public:
    //构造
    TcpServer(int port)
    :_port(port)
    ,_listensockfd(defaultsockfd)
    ,_isrunning(false)
    {

    }
        void Service(int sockfd,InetAddr client)
    {
        LOG(DEBUG,"get a link,info:%s:%d,sockfd:%d\n",client.Ip().c_str(),client.Port(),sockfd);
        std::string clientaddr = "["+client.Ip()+":"+std::to_string(client.Port())+"]#";
        while(true)
        {
            char inbuffer[1024];
            ssize_t n = read(sockfd,inbuffer,sizeof(inbuffer)-1);
            if(n>0)//接收成功
            {
                inbuffer[n]=0;
                std::cout<<clientaddr<<inbuffer<<std::endl;//输出client信息
                std::string echo_string="[server echo]#";//server输出界面
                echo_string += inbuffer;
                write(sockfd,echo_string.c_str(),echo_string.size());
            }
            else if(n == 0)
            {
                //读到结尾
                //client退出&&关闭连接
                LOG(INFO,"%s is quit\n",clientaddr.c_str());
                break;
            }
            else
            {   //接收失败
                LOG(ERROR, "read error\n");
                break;
            }
        }
        close(sockfd);//预防文件描述符泄露
    }

    void InitServer()
    {
        //创建套接字
        _listensockfd = socket(AF_INET,SOCK_STREAM,0);
        if(_listensockfd<0)//创建失败
        {
            LOG(FATAL,"socket error\n");
            exit(SOCKET_ERROR);
        }
        //构造client端的struct addr_in
        struct sockaddr_in local;
        bzero(&local,sizeof(local));
        local.sin_family = AF_INET;//网络通讯方式为ipv4
        local.sin_port = htons(_port);//主机序列转网络序列
        local.sin_addr.s_addr=INADDR_ANY;
        //0.0.0.0,绑定所有网络接口，无论client通过哪个ip进来都可以访问
        //bind
        int n = bind(_listensockfd,(struct sockaddr *)&local,sizeof(local));
        if(n<0)
        {
            LOG(FATAL,"bind error\n");
            exit(BIND_ERROR);
        }
        //tcp还需要另外一步listen(listen所用的套接字就是listensockfd)
        
        n = listen(_listensockfd,gbacklog);
        if(n<0)
        {
            //监听失败报错退出
            LOG(FATAL,"listen error\n");
            exit(LISTEN_ERROR);
        }
        LOG(DEBUG, "listen success,sockfd is : %d\n", _listensockfd);
    }

    void Loop()
    {
        _isrunning = true;
        while(_isrunning)
        {
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer); 
            int sockfd =::accept(_listensockfd,(struct sockaddr*)&peer,&len);
            if(sockfd<0)
            {
                //
                LOG(WARNING,"accept error\n");
                continue;
            }
            Service(sockfd,InetAddr(peer));
        }
        _isrunning = false;
    }
    //析构
    ~TcpServer()
    {
        if(_listensockfd>=0)
            close(_listensockfd);
    }
private:
    int _port;
    int _listensockfd;//命名为listensockfd是有原因的
    bool _isrunning;
};